﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TempMonitor
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        const string label7Str = "当前状态：";
        const string label8Str = "数据状态：";
        const int collectIntervalMax = 1800;//分钟
        const int collectCountMax = 1000;
        const byte writeHoldingRegisterResponseDataLength = 8;
        const int delayTime = 500;
        const int deviceAddrMax = 31;

        int thisFormWidth = 0;
        byte deviceAddr = 1;

        Dictionary<string, string> dataList = new Dictionary<string, string>();
        Dictionary<string, int> activeDeviceList = new Dictionary<string, int>();
        //饱和蒸气压, 一行20个数据，从0度开始，到150度结束，共151个
        float[] PS = { 0.61129F,0.65716F,0.70605F,0.75813F,0.81359F,0.87260F,0.93537F,1.0021F,1.0730F,1.1482F,1.2281F,1.3129F,1.4027F,1.4979F,1.5988F,1.7056F,1.8185F,1.9380F,2.0644F,2.1978F,
        2.3388F,2.4877F,2.6447F, 2.8104F,2.985F,3.169F,3.3629F,3.5670F,3.7818F,4.0078F,4.2455F,4.4953F,4.7578F,5.0335F,5.3229F,5.6267F,5.9453F,6.2795F,6.6298F,6.9969F,
        7.3814F,7.7840F,8.2054F,8.6463F,9.1075F,9.5898F,10.094F,10.620F,11.171F,11.745F,12.344F,12.970F,13.623F,14.303F,15.012F,15.752F,16.522F,17.324F,18.159F,19.028F,
        19.932F,20.873F,21.851F,22.868F,23.925F,25.022F,26.163F,27.347F,28.576F,29.852F,31.176F,32.549F,33.972F,35.448F,36.978F,38.563F,40.205F,41.905F,43.665F,45.487F,
        47.373F,49.324F,51.342F,53.428F,55.585F,57.815F,60.119F,62.499F,64.958F,67.496F,70.117F,72.823F,75.614F,78.494F,81.465F,84.529F,87.688F,90.945F,94.301F,97.759F,
        101.32F,104.99F,108.77F,112.66F,116.67F,120.79F,125.03F,129.39F,133.88F,138.50F,143.24F,148.12F,153.13F,158.29F,163.58F,169.02F,174.61F,180.34F,186.23F,192.28F,
        198.48F,204.85F,211.38F,218.09F,224.96F,232.01F,239.24F,246.66F,254.25F,262.04F,270.02F,278.20F,286.57F,295.15F,303.93F,312.93F,322.14F,331.57F,341.22F,351.09F,
        361.19F,371.53F,382.11F,392.92F,403.98F,415.29F,426.85F,438.67F,450.75F,463.10F,475.72F};

        private bool isNumber(string s)
        {
            char[] str = s.ToCharArray();
            for (int i = 0; i < str.Length; i++)
            {
                if (Char.IsNumber(str[i]) == false)
                {
                    return false;
                }
            }
            return true;
        }

        private bool OpenSerial()
        {
            if (!serialPort1.IsOpen)
            {
                try
                {
                    string portName = "";
                    this.Invoke(new Action(() =>
                    {
                        portName = comboBox1.Text.Trim();
                    }));
                    if (portName != "")
                    {
                        //串口的设置
                        serialPort1.PortName = portName;
                        serialPort1.BaudRate = 9600;
                        serialPort1.Parity = Parity.None;
                        serialPort1.DataBits = 8;
                        serialPort1.StopBits = StopBits.One;

                        serialPort1.Open();
                    }
                    else
                    {
                        this.Invoke(new Action(() =>
                        {
                            label7.Text = label7Str + "串口未选择";
                        }));
                        Log.WriteLog("串口未选择:");
                        return false;
                    }
                }
                catch (Exception msg)
                {
                    this.Invoke(new Action(() =>
                    {
                        label7.Text = label7Str + msg.Message;
                    }));
                    Log.WriteLog("打开串口异常:");
                    Log.WriteLog(msg.Message);
                    Log.WriteLog(msg.StackTrace);
                    serialPort1.Close();
                    return false;
                }
            }
            Log.WriteLog("串口已打开。");
            this.Invoke(new Action(() =>
            {
                label7.Text = label7Str + "";
            }));
            timer1.Stop();//说明已找到正确的端口，可以关闭定时器
            return true;
        }

        private bool SendWriteHoldingRegisterDataAndVerify(byte[] sendData, UInt16 registerStartAddr, UInt16 registerCount)
        {
            serialPort1.ReadExisting();//清空缓存
            serialPort1.Write(sendData, 0, sendData.Length);

            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(100);
                int len = serialPort1.BytesToRead;
                if (len >= writeHoldingRegisterResponseDataLength)
                {
                    byte[] recData = new byte[len];
                    serialPort1.Read(recData, 0, len);

                    UInt16 crc = modbus.Get_Crc_16(recData, writeHoldingRegisterResponseDataLength - 2);
                    UInt16 crcData = (UInt16)(recData[writeHoldingRegisterResponseDataLength - 1] + recData[writeHoldingRegisterResponseDataLength - 2] * 256);
                    if (crc != crcData)
                    {
                        string tmp = string.Format("CRC:{0:X},CRC check:{0:X}", crcData, crc);
                        Log.WriteLog("返回的CRC不对--" + tmp);
                        return false;
                    }
                    if (recData[0] != deviceAddr || recData[1] != modbus.WriteMultipleRegister)
                    {
                        Log.WriteLog("返回的设备地址或者功能码不对。");
                        return false;
                    }
                    UInt16 startAddr = (UInt16)(recData[2] * 256 + recData[3]);
                    if (startAddr != registerStartAddr)
                    {
                        Log.WriteLog("返回的设备起始地址不对。");
                        return false;
                    }
                    UInt16 regCount = (UInt16)(recData[4] * 256 + recData[5]);
                    if (regCount != registerCount)
                    {
                        Log.WriteLog("返回的寄存器数量不对。");
                        return false;
                    }
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 设置当前时间
        /// </summary>
        /// <returns></returns>
        private bool SetDateTimeToDevice()
        {
            const UInt16 registerStartAddr = 7;
            byte[] data = new byte[6];
            DateTime dt = DateTime.Now;
            data[0] = (byte)(dt.Year % 100);//年
            data[1] = (byte)(dt.Month);
            data[2] = (byte)(dt.Day);
            data[3] = (byte)(dt.Hour);
            data[4] = (byte)(dt.Minute);
            data[5] = (byte)(dt.Second);
            string dtStr = string.Format("设置时间:20{0:D2}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}", data[0], data[1], data[2], data[3], data[4], data[5]);
            Log.WriteLog(dtStr);
            byte[] sendData = modbus.GetDataForWriteHoldingRegister(deviceAddr, registerStartAddr, 3, 6, data);
            if (SendWriteHoldingRegisterDataAndVerify(sendData, registerStartAddr, 3) == true)
            {
                string timeStr = "";
                Thread.Sleep(delayTime);
                ReadCurrentTimeFromDevice(ref timeStr);
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 开始采集时间
        /// </summary>
        /// <returns></returns>
        private bool SetCollectDateTimeToDevice()
        {
            const UInt16 registerStartAddr = 10;
            byte[] data = new byte[6];
            DateTime dt = dateTimePicker1.Value;

            data[0] = (byte)(dt.Year % 100);//年
            data[1] = (byte)(dt.Month);
            data[2] = (byte)(dt.Day);
            data[3] = (byte)(dt.Hour);
            data[4] = (byte)(dt.Minute);
            data[5] = (byte)(dt.Second); ;
            string dtStr = string.Format("设置开始采集时间:20{0:D2}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}", data[0], data[1], data[2], data[3], data[4], data[5]);
            Log.WriteLog(dtStr);
            byte[] sendData = modbus.GetDataForWriteHoldingRegister(deviceAddr, registerStartAddr, 3, 6, data);
            if (SendWriteHoldingRegisterDataAndVerify(sendData, registerStartAddr, 3) == true)
            {
                string timeStr = "";
                Thread.Sleep(delayTime);
                ReadCollectStartTimeFromDevice(ref timeStr);
                Log.WriteLog("读取出来的时间是：" + timeStr);
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 计划采集数据个数
        /// </summary>
        /// <returns></returns>
        private bool SetCollectCountToDevice()
        {
            const UInt16 registerStartAddr = 15;
            byte[] data = new byte[2];
            UInt16 count = Convert.ToUInt16(textBox2.Text.Trim());
            data[0] = (byte)(count >> 8);//高位
            data[1] = (byte)(count & 0xff);
            Log.WriteLog("设置计划采集数据个数:" + count.ToString());
            byte[] sendData = modbus.GetDataForWriteHoldingRegister(deviceAddr, registerStartAddr, 1, 2, data);
            if (SendWriteHoldingRegisterDataAndVerify(sendData, registerStartAddr, 1) == true)
            {
                int countOfData = 0;
                Thread.Sleep(delayTime);
                if (ReadPlanCountOfDataFromDevice(ref countOfData) == true)
                {
                    if (countOfData == count)
                    {
                        return true;
                    }
                    else
                    {
                        Log.WriteLog("回读计划采集的个数出错。跟设置的不一致：" + countOfData.ToString());
                        return false;
                    }
                }
                else
                {
                    Log.WriteLog("回读计划采集的个数出错。");
                    return false;
                }
            }
            return false;
        }

        /// <summary>
        /// 采集时间间隔
        /// </summary>
        /// <returns></returns>
        private bool SetCollectIntervalToDevice()
        {
            const UInt16 registerStartAddr = 13;
            byte[] data = new byte[2];
            UInt16 interval = Convert.ToUInt16(textBox1.Text.Trim());
            data[0] = (byte)(interval >> 8);//高位
            data[1] = (byte)(interval & 0xff);
            Log.WriteLog("设置采集时间间隔：" + interval.ToString());
            byte[] sendData = modbus.GetDataForWriteHoldingRegister(deviceAddr, registerStartAddr, 1, 2, data);
            if (SendWriteHoldingRegisterDataAndVerify(sendData, registerStartAddr, 1) == true)
            {
                Thread.Sleep(delayTime);
                int intervalReturn = 0;
                if (ReadCollectIntervalFromDevice(ref intervalReturn) == true)
                {
                    if (interval == intervalReturn)
                    {
                        return true;
                    }
                    else
                    {
                        Log.WriteLog("回读收集时间间隔跟设置的不一致：" + intervalReturn.ToString());
                        return false;
                    }
                }
                else
                {
                    Log.WriteLog("回读收集时间间隔出错。");
                    return false;
                }
            }
            else
            {
                return false;
            }

        }

        /// <summary>
        /// 写入非0数值清零 并按照配置启动采集
        /// </summary>
        /// <returns></returns>
        private bool StartCollect()
        {
            const UInt16 registerStartAddr = 14;
            byte[] data = new byte[2];
            data[0] = 1;//高位
            data[1] = 1;
            Log.WriteLog("写入非0数值清零 并按照配置启动采集。");
            byte[] sendData = modbus.GetDataForWriteHoldingRegister(deviceAddr, registerStartAddr, 1, 2, data);
            return SendWriteHoldingRegisterDataAndVerify(sendData, registerStartAddr, 1);
        }

        private void SetConfigAndStartCollect()
        {
            Log.WriteLog("开始配置数据并启动采集。");
            string status = "";
            try
            {
                if (OpenSerial() == true)
                {
                    if (SetCollectIntervalToDevice() == false)
                    {
                        status = "设置采集时间间隔出错。";
                        Log.WriteLog(status);
                    }
                    else
                    {
                        Thread.Sleep(delayTime);
                        if (SetCollectCountToDevice() == false)
                        {
                            status = "设置采集个数出错。";
                            Log.WriteLog(status);
                        }
                        else
                        {
                            Thread.Sleep(delayTime);
                            if (SetDateTimeToDevice() == false)
                            {
                                status = "设置时间出错。";
                                Log.WriteLog(status);
                            }
                            else
                            {
                                Thread.Sleep(delayTime);
                                if (SetCollectDateTimeToDevice() == false)
                                {
                                    status = "设置开始采集时间出错。";
                                    Log.WriteLog(status);
                                }
                                else
                                {
                                    Thread.Sleep(delayTime);
                                    if (StartCollect() == false)
                                    {
                                        status = "设置开始采集出错。";
                                        Log.WriteLog(status);
                                    }
                                    else
                                    {
                                        int time = Convert.ToInt32(textBox1.Text.Trim()) * Convert.ToInt32(textBox2.Text.Trim());
                                        DateTime dtFinished = dateTimePicker1.Value.AddSeconds(time);
                                        status = "开始采集设置成功！\r\n预计结束时间是：" + dtFinished.ToString("yyyy-MM-dd HH:mm:ss");
                                    }
                                }
                            }
                        }
                    }
                    serialPort1.Close();
                }
                else
                {
                    status = "打开串口出错！";
                    Log.WriteLog(status);
                    serialPort1.Close();
                }
            }
            catch (Exception ex)
            {
                serialPort1.Close();
                Log.WriteLog(ex.Message);
                Log.WriteLog(ex.StackTrace);
                status = ex.Message;
            }

            this.Invoke(new Action(() =>
            {
                label7.Text = label7Str + status;
                button3.Enabled = true;
                panel7.Visible = false;
            }));
        }

        private bool SendReadHoldingRegisterDataAndVerify(byte[] sendData, UInt16 registerStartAddr, UInt16 registerCount, ref byte recDataLen, ref byte[] receiveData)
        {
            serialPort1.ReadExisting();//清空缓存
            serialPort1.Write(sendData, 0, sendData.Length);

            /* 返回的数据
             * 从机地址	 功能号	数据字节个数(1字节)	字节数据(寄存器先发送的先回来)	CRC校验 */
            int receiveDataLength = 5 + registerCount * 2;

            for (int i = 0; i < (2 + registerCount); i++)
            {
                Thread.Sleep(100);
                int len = serialPort1.BytesToRead;
                if (len >= receiveDataLength)
                {
                    byte[] readData = new byte[len];
                    serialPort1.Read(readData, 0, len);

                    UInt16 crc = modbus.Get_Crc_16(readData, receiveDataLength - 2);
                    UInt16 crcData = (UInt16)(readData[receiveDataLength - 1] + readData[receiveDataLength - 2] * 256);
                    if (crc != crcData)
                    {
                        string tmp = string.Format("CRC:{0:X},CRC check:{0:X}", crcData, crc);
                        Log.WriteLog("返回的CRC不对--" + tmp);
                        return false;
                    }
                    if (readData[0] != deviceAddr || readData[1] != modbus.ReadHoldingRegister)
                    {
                        Log.WriteLog("返回的设备地址或者功能码不对。");
                        return false;
                    }
                    recDataLen = readData[2];
                    Array.Copy(readData, 3, receiveData, 0, recDataLen);
                    return true;
                }
            }

            return false;
        }

        private bool SendCheckDeviceAddrMsg(byte[] sendData, UInt16 registerCount, ref byte recDataLen, ref byte[] receiveData)
        {
            serialPort1.ReadExisting();//清空缓存
            serialPort1.Write(sendData, 0, sendData.Length);

            /* 返回的数据
             * 从机地址	 功能号	数据字节个数(1字节)	字节数据(寄存器先发送的先回来)	CRC校验 */
            int receiveDataLength = 5 + registerCount * 2;

            for (int i = 0; i < (2 + registerCount); i++)
            {
                Thread.Sleep(100);
                int len = serialPort1.BytesToRead;
                if (len >= receiveDataLength)
                {
                    byte[] readData = new byte[len];
                    serialPort1.Read(readData, 0, len);

                    UInt16 crc = modbus.Get_Crc_16(readData, receiveDataLength - 2);
                    UInt16 crcData = (UInt16)(readData[receiveDataLength - 1] + readData[receiveDataLength - 2] * 256);
                    if (crc != crcData)
                    {
                        string tmp = string.Format("CRC:{0:X},CRC check:{0:X}", crcData, crc);
                        Log.WriteLog("返回的CRC不对--" + tmp);
                        return false;
                    }
                    if (readData[1] != 0x64)//功能码自定义
                    {
                        Log.WriteLog("返回的功能码不对。");
                        return false;
                    }
                    recDataLen = readData[2];
                    Array.Copy(readData, 3, receiveData, 0, recDataLen);
                    return true;
                }
            }

            return false;
        }

        private bool ReadPlanCountOfDataFromDevice(ref int countOfData)
        {
            const UInt16 registerStartAddr = 15;
            Log.WriteLog("开始从设备里读取计划采集的数据个数。");
            byte[] data = modbus.GetDataForReadHoldingRegister(deviceAddr, registerStartAddr, 1);
            byte[] receiveData = new byte[2]; //只有2个字节
            byte receiveDataLength = 0;
            bool returnValue = SendReadHoldingRegisterDataAndVerify(data, registerStartAddr, 1, ref receiveDataLength, ref receiveData);
            if (returnValue == true && receiveDataLength == 2)
            {
                countOfData = receiveData[0] * 256 + receiveData[1];
                Log.WriteLog("设备计划采集" + countOfData.ToString() + "条数据");
                if (countOfData == 0)
                {
                    Log.WriteLog("计划采集的数据个数是0。");
                    return false;
                }
            }
            else
            {
                Log.WriteLog("读取计划采集的数据个数：数据长度不对或没有收到数据。");
                return false;
            }
            return returnValue;
        }

        private bool ReadCountOfDataFromDevice(ref int countOfData)
        {
            const UInt16 registerStartAddr = 16;
            Log.WriteLog("开始从设备里读取采集的数据个数。");
            byte[] data = modbus.GetDataForReadHoldingRegister(deviceAddr, registerStartAddr, 1);
            byte[] receiveData = new byte[2]; //只有2个字节
            byte receiveDataLength = 0;
            bool returnValue = SendReadHoldingRegisterDataAndVerify(data, registerStartAddr, 1, ref receiveDataLength, ref receiveData);
            if (returnValue == true && receiveDataLength == 2)
            {
                countOfData = receiveData[0] * 256 + receiveData[1];
                Log.WriteLog("设备里存在" + countOfData.ToString() + "条数据");
                if (countOfData > collectCountMax)
                {
                    Log.WriteLog("读取采集的数据个数大于可以存储的个数。");
                    return false;
                }
                if (countOfData == 0)
                {
                    Log.WriteLog("读取采集的数据个数是0。");
                    return false;
                }
            }
            else
            {
                Log.WriteLog("读取采集的数据个数：数据长度不对或没有收到数据。");
                return false;
            }
            return returnValue;
        }

        private bool ReadCurrentTimeFromDevice(ref string currentTimeStr)
        {
            const UInt16 registerStartAddr = 7;
            const byte registerCount = 3;
            const byte dataLength = 2 * registerCount;
            Log.WriteLog("开始从设备里读取当前时间。");
            byte[] data = modbus.GetDataForReadHoldingRegister(deviceAddr, registerStartAddr, registerCount);
            byte[] receiveData = new byte[dataLength]; //只有6个字节
            byte receiveDataLength = 0;
            bool returnValue = SendReadHoldingRegisterDataAndVerify(data, registerStartAddr, registerCount, ref receiveDataLength, ref receiveData);
            if (returnValue == true && receiveDataLength == dataLength)
            {
                currentTimeStr = string.Format("20{0:D2}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}", receiveData[0], receiveData[1], receiveData[2], receiveData[3], receiveData[4], receiveData[5]);
                Log.WriteLog("设备当前时间：" + currentTimeStr);
            }
            else
            {
                Log.WriteLog("读取设备当前时间：数据长度不对或没有收到数据。");
                return false;
            }
            return returnValue;
        }

        private bool ReadCollectStartTimeFromDevice(ref string collectTimeStr)
        {
            const UInt16 registerStartAddr = 10;
            const byte registerCount = 3;
            const byte dataLength = 2 * registerCount;
            Log.WriteLog("开始从设备里读取采集的开始时间。");
            byte[] data = modbus.GetDataForReadHoldingRegister(deviceAddr, registerStartAddr, registerCount);
            byte[] receiveData = new byte[dataLength]; //只有6个字节
            byte receiveDataLength = 0;
            bool returnValue = SendReadHoldingRegisterDataAndVerify(data, registerStartAddr, registerCount, ref receiveDataLength, ref receiveData);
            if (returnValue == true && receiveDataLength == dataLength)
            {
                collectTimeStr = string.Format("20{0:D2}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}", receiveData[0], receiveData[1], receiveData[2], receiveData[3], receiveData[4], receiveData[5]);
                Log.WriteLog("设备开始采集的时间：" + collectTimeStr);
            }
            else
            {
                Log.WriteLog("读取采集的开始时间：数据长度不对或没有收到数据。");
                return false;
            }
            return returnValue;
        }

        private bool ReadCollectIntervalFromDevice(ref int collectInterval)
        {
            const UInt16 registerStartAddr = 13;
            Log.WriteLog("开始从设备里读取采集时间间隔。");
            byte[] data = modbus.GetDataForReadHoldingRegister(deviceAddr, registerStartAddr, 1);
            byte[] receiveData = new byte[2]; //只有2个字节
            byte receiveDataLength = 0;
            bool returnValue = SendReadHoldingRegisterDataAndVerify(data, registerStartAddr, 1, ref receiveDataLength, ref receiveData);
            if (returnValue == true && receiveDataLength == 2)
            {
                collectInterval = receiveData[0] * 256 + receiveData[1];
                Log.WriteLog("从设备里读取到的采集时间间隔为" + collectInterval.ToString());
            }
            else
            {
                Log.WriteLog("读取采集的采集时间间隔：数据长度不对或没有收到数据。");
                return false;
            }
            return returnValue;
        }

        private bool ReadCollectDataFromDevice(int countOfData, Int16[] temperatureData)
        {
            //每次最多读100组数据，也就是200个字节
            UInt16 registerStartAddr = 100;//采集数据0000
            Log.WriteLog("开始从设备里读取采集的数据。");
            UInt16 registerCount = 0;
            byte dataLength = 0;
            byte receiveDataLength = 0;
            int loop = (countOfData / 100) + 1;//最多进行这么多次循环
            int dataIndex = 0;
            for (int i = 0; i < loop; i++)
            {
                if (i == (loop - 1))//最后一组
                {
                    registerCount = (UInt16)(countOfData % 100);
                }
                else
                {
                    registerCount = 100;
                }
                byte[] data = modbus.GetDataForReadHoldingRegister(deviceAddr, registerStartAddr, registerCount);
                dataLength = (byte)(2 * registerCount);
                byte[] receiveData = new byte[dataLength];
                bool returnValue = SendReadHoldingRegisterDataAndVerify(data, registerStartAddr, registerCount, ref receiveDataLength, ref receiveData);
                if (returnValue == true && receiveDataLength == dataLength)
                {
                    Log.WriteLog("读取" + registerCount.ToString() + "个采集的数据，寄存器起始地址：" + registerStartAddr.ToString());
                    for (int k = 0; k < registerCount; k++)
                    {
                        /*
                        bool isNegative = false;
                        if ((receiveData[k * 2] & 0x80) == 0x80)
                        {
                            isNegative = true;
                        }
                        byte noNegative = (byte)(receiveData[k * 2] & 0x7F);
                        Int16 value = (Int16)(noNegative * 256 + receiveData[k * 2 + 1]);
                        if (isNegative == true)
                        {
                            value = (Int16)(0 - value);
                        }*/
                        UInt16 temp = (UInt16)(receiveData[k * 2] * 256 + receiveData[k * 2 + 1]);
                        Log.WriteLog(temp.ToString());
                        temperatureData[dataIndex + k] = (Int16)temp;
                    }
                }
                else
                {
                    Log.WriteLog("读取采集的数据：数据长度不对或没有收到数据。");
                    return false;
                }
                dataIndex += 100;
                registerStartAddr += 100;
            }
            return true;
        }

        private void ReadDataFromDevice()
        {
            Log.WriteLog("开始从设备读取数据。");
            string status = "";
            int countOfData = 0;
            int collectInterval = 0;
            string collectTimeStr = "";
            Int16[] temperatureData = new Int16[collectCountMax];

            try
            {
                if (OpenSerial() == true)
                {
                    if (ReadCountOfDataFromDevice(ref countOfData) == false)
                    {
                        status = "获取设备上的采集数据个数出错。";
                        Log.WriteLog(status);
                    }
                    else
                    {
                        Thread.Sleep(delayTime);
                        if (ReadCollectStartTimeFromDevice(ref collectTimeStr) == false)
                        {
                            status = "读取设备上的采集开始时间出错。";
                            Log.WriteLog(status);
                        }
                        else
                        {
                            Thread.Sleep(delayTime);
                            DateTime dt = DateTime.Parse(collectTimeStr);
                            if (ReadCollectIntervalFromDevice(ref collectInterval) == false)
                            {
                                status = "读取设备上的采集间隔时间出错。";
                                Log.WriteLog(status);
                            }
                            else
                            {
                                Thread.Sleep(delayTime);
                                if (ReadCollectDataFromDevice(countOfData, temperatureData) == false)
                                {
                                    status = "读取设备上的数据出错。";
                                    Log.WriteLog(status);
                                }
                                else
                                {
                                    //写数据到文件
                                    string logFilePath = "./data";
                                    if (!Directory.Exists(logFilePath))
                                    {
                                        Directory.CreateDirectory(logFilePath);//创建该文件夹
                                    }
                                    DateTimeOffset dto = new DateTimeOffset(dt);
                                    long timeStamp = dto.ToUnixTimeSeconds();
                                    string fileName = "device_" + deviceAddr.ToString() + "_" + dt.ToString("yyyy-MM-dd") + "_" + timeStamp.ToString() + ".dt";
                                    string filePath = logFilePath + "/" + fileName;
                                    if (File.Exists(filePath) == false)
                                    {
                                        StreamWriter swLogFile = new StreamWriter(filePath, true, Encoding.Unicode);
                                        swLogFile.WriteLine(dt.ToString("yyyy-MM-dd HH:mm:ss"));//第1行写入采集时间
                                        swLogFile.WriteLine(collectInterval.ToString() + " " + countOfData.ToString());//第2行写入采集间隔和个数
                                        for (int i = 0; i < countOfData; i++)
                                        {
                                            swLogFile.WriteLine(temperatureData[i].ToString());
                                        }
                                        swLogFile.Flush();
                                        swLogFile.Close();
                                        swLogFile.Dispose();
                                        status = "数据保存成功！一共成功读取" + countOfData.ToString() + "个数据！";
                                    }
                                    else
                                    {
                                        status = "数据" + "device_" + deviceAddr.ToString() + "_" + dt.ToString("yyyy-MM-dd HH:mm:ss") + "已经存在，无需重复读取！";
                                    }
                                }
                            }
                        }
                    }
                    serialPort1.Close();
                }
                else
                {
                    status = "打开串口出错！";
                    Log.WriteLog(status);
                    serialPort1.Close();
                }
            }
            catch (Exception ex)
            {
                Log.WriteLog(ex.Message);
                Log.WriteLog(ex.StackTrace);
                serialPort1.Close();
            }

            this.Invoke(new Action(() =>
            {
                label8.Text = label8Str + status;
                button4.Enabled = true;
                ScanDataFiles(false);
                panel7.Visible = false;
            }));
        }


        private void ScanDataFiles(bool showStatus)
        {
            dataList.Clear();
            comboBox2.Text = "";
            comboBox2.Items.Clear();

            string[] files = System.IO.Directory.GetFiles("./data", "*.dt");
            Log.WriteLog("扫描到" + files.Length.ToString() + "个文件");
            foreach (string file in files)
            {
                string[] tmp = file.Split('_');
                if (tmp.Length == 4)
                {
                    string[] fileName = tmp[3].Split('.');
                    if (fileName.Length == 2)
                    {
                        DateTimeOffset dto = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt64(fileName[0]));
                        DateTime dt = dto.LocalDateTime;
                        string key = "device_" + tmp[1] + "_" + dt.ToString("yyyy-MM-dd HH:mm:ss");
                        dataList.Add(key, file);
                        comboBox2.Items.Add(key);
                    }
                    else
                    {
                        Log.WriteLog("解析时间戳出错！" + file);
                    }
                }
                else
                {
                    Log.WriteLog("解析文件名出错！" + file);
                }
            }

            if (comboBox2.Items.Count != 0)
            {
                comboBox2.SelectedIndex = 0;
            }
            if (showStatus == true)
            {
                label8.Text = label8Str + "一共有" + dataList.Count.ToString() + "组数据。";
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            VersionToolStripMenuItem.Text = "程序版本" + Application.ProductVersion.ToString();
            foreach (string portName in SerialPort.GetPortNames())
            {
                comboBox1.Items.Add(portName);
            }
            if (comboBox1.Items.Count != 0)
            {
                comboBox1.SelectedIndex = 0;
            }

            if (Directory.Exists("./data") == false)
            {
                Directory.CreateDirectory("./data");
            }

            Log.OpenLog();

            ScanDataFiles(true);

            thisFormWidth = this.Width;

            timer1.Start();

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Log.CloseLog();
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            if (textBox1.Text.Length != 0)
            {
                if (isNumber(textBox1.Text.Trim()) == false)
                {
                    MessageBox.Show("请输入数字!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    textBox1.Text = "60";
                    return;
                }
                int minutes = Convert.ToInt32(textBox1.Text.Trim());
                if (minutes > collectIntervalMax)
                {
                    string hint = "最大间隔不能超过" + collectIntervalMax.ToString() + "秒！";
                    MessageBox.Show(hint, "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    textBox1.Text = "60";
                    return;
                }
                if (minutes == 0)
                {
                    MessageBox.Show("不能设置为0秒！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    textBox1.Text = "60";
                    return;
                }
            }
        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            if (textBox2.Text.Length != 0)
            {
                if (isNumber(textBox2.Text.Trim()) == false)
                {
                    MessageBox.Show("请输入数字!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    textBox2.Text = "1000";
                    return;
                }
                int counts = Convert.ToInt32(textBox2.Text.Trim());
                if (counts > collectCountMax)
                {
                    string hint = "最大个数不能超过" + collectIntervalMax.ToString() + "！";
                    MessageBox.Show(hint, "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    textBox2.Text = "1000";
                    return;
                }
                if (counts == 0)
                {
                    MessageBox.Show("不能设置为0个！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    textBox2.Text = "1000";
                    return;
                }
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            DateTime dt = DateTime.Now.AddSeconds(60);
            if (dateTimePicker1.Value < dt)
            {
                MessageBox.Show("设置的采集时间不能早于当前时间1分钟！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            if (comboBox3.Items.Count != 0)
            {
                string[] tmp = comboBox3.Text.Split('_');
                if (tmp.Length == 2)
                {
                    deviceAddr = Convert.ToByte(tmp[1]);
                    Thread thread = new Thread(new ThreadStart(SetConfigAndStartCollect));
                    thread.Start();
                    button3.Enabled = false;
                    panel7.Visible = true;
                }
                else
                {
                    MessageBox.Show("当前设备地址无效，需要先侦测在线设备！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
            else
            {
                MessageBox.Show("当前在线设备为0，需要先侦测在线设备！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        //从设备读取数据
        private void button4_Click(object sender, EventArgs e)
        {
            if (comboBox3.Items.Count != 0)
            {
                string[] tmp = comboBox3.Text.Split('_');
                if (tmp.Length == 2)
                {
                    deviceAddr = Convert.ToByte(tmp[1]);
                    Thread thread = new Thread(new ThreadStart(ReadDataFromDevice));
                    thread.Start();
                    button4.Enabled = false;
                    panel7.Visible = true;
                }
                else
                {
                    MessageBox.Show("当前设备地址无效，需要先侦测在线设备！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
            else
            {
                MessageBox.Show("当前在线设备为0，需要先侦测在线设备！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ScanDataFiles(true);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (comboBox2.Items.Count > 0)
            {
                try
                {
                    string fileName = dataList[comboBox2.Text];
                    // 创建一个 StreamReader 的实例来读取文件 
                    // using 语句也能关闭 StreamReader
                    using (StreamReader sr = new StreamReader(fileName))
                    {
                        string line;
                        line = sr.ReadLine();//第一行
                        DateTime dt = DateTime.Parse(line);
                        line = sr.ReadLine();//第2行是采集间隔和采集个数
                        string[] tmp = line.Split(' ');
                        if (tmp.Length == 2)
                        {
                            int collectInterval = Convert.ToInt32(tmp[0]);
                            int countOfData = Convert.ToInt32(tmp[1]);
                            string status = string.Format("读取文件:{0},共有{1}个数据，采集间隔为:{2}", fileName, countOfData, countOfData);
                            Log.WriteLog(status);
                            float[] data = new float[countOfData];
                            float[] dataSort = new float[countOfData];
                            DateTime[] times = new DateTime[countOfData];
                            int count = 0;
                            // 从文件读取每一行，直到文件的末尾 
                            while ((line = sr.ReadLine()) != null)
                            {
                                if (count >= countOfData)
                                {
                                    Log.WriteLog("读取文件出错：数据溢出！");
                                    MessageBox.Show("读取文件出错：数据溢出！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                                    break;
                                }
                                else
                                {
                                    data[count] = (float)((Convert.ToInt16(line)) / 100.0);
                                    times[count] = dt.AddSeconds(collectInterval * count);
                                }
                                count++;
                            }
                            Array.Copy(data, dataSort, data.Length);
                            Array.Sort(dataSort);

                            float minValue = dataSort[0];
                            float maxValue = dataSort[countOfData - 1];
                            if (minValue > 0)
                            {
                                minValue = Convert.ToInt32(minValue) - (Convert.ToInt32(minValue) % 10) - 5;
                            }
                            else
                            {
                                minValue = Convert.ToInt32(minValue) - (Convert.ToInt32(minValue) % 10) - 10;
                            }
                            maxValue = Convert.ToInt32(maxValue) + (10 - Convert.ToInt32(maxValue) % 10) + 5;
                            if (maxValue < 0)
                                maxValue = 1;

                            float[] humiData = Calculate_Humi(data);

                            // 设置曲线属性，名称，数据，颜色，是否平滑，格式化显示文本
                            hslCurveHistory1.SetLeftCurve("温度", data, Color.DodgerBlue, HslControls.CurveStyle.Curve, "{0:F2} ℃");
                            hslCurveHistory1.SetRightCurve("绝对湿度", humiData, Color.BlueViolet, HslControls.CurveStyle.Curve, "{0:F2}");
                            hslCurveHistory1.ValueMaxLeft = maxValue;
                            hslCurveHistory1.ValueMinLeft = minValue;
                            hslCurveHistory1.SetDateTimes(times);
                            float scale = (thisFormWidth - 150) / countOfData;//图宽度大概是900个像素，每个点是1个像素，如果有30个，那么每个点需要占据26个像素点才能填满整个曲线图
                            hslCurveHistory1.SetScaleByXAxis(scale);//缩放
                            hslCurveHistory1.RenderCurveUI();

                            label8.Text = label8Str + "当前显示的数据是：" + comboBox2.Text;
                        }
                        else
                        {
                            Log.WriteLog("读取文件出错：格式不对！");
                            MessageBox.Show("读取文件出错：格式不对！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.WriteLog(ex.Message);
                    Log.WriteLog(ex.StackTrace);
                    MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
            else
            {
                string hint = "当前没有数据！";
                MessageBox.Show(hint, "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        /*用饱和蒸气压算出饱和绝对湿度，与绝对湿度比可得相对湿度

        饱和绝对湿度 ρs = Ps / (Rv * T)
        其中Ps是饱和蒸气压，Rv是湿空气的气体常数，T是温度
        Rv = 287 /（1-0.378*Pv/B)
        Pv是蒸气压，文档中不同温度下的蒸气压，B是湿空气的总压力，当前是一个标准大气压，101.325kPa，后续这个值可变
        绝对湿度ρv = ρs * φ, ρv是绝对湿度，φ是相对湿度，传感器测试值*/
        private float[] Calculate_Humi(float[] tempData)
        {
            float[] data = new float[tempData.Length];
            for(int i=0;i<data.Length;i++)
            {
                int temp = (int)tempData[i];
                float PV = PS[temp];
                float Rv = (float)(287 / ((1 - 0.378)*PV/ 101.325));
                data[i] = tempData[i] - 10;
            }
            return data;
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            thisFormWidth = this.Width;
        }

        private void button5_Click_1(object sender, EventArgs e)
        {
            if (comboBox2.Items.Count > 0)
            {
                string fileName = dataList[comboBox2.Text];
                string warningStr = "确定要删除数据\"" + comboBox2.Text + "\"吗？\r\n删除后不能恢复，请谨慎操作！";
                DialogResult result = MessageBox.Show(warningStr, "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                if (result == DialogResult.Yes)
                {
                    File.Delete(fileName);
                    warningStr = "数据\"" + comboBox2.Text + "\"已删除！";
                    MessageBox.Show(warningStr, "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
                ScanDataFiles(true);
            }
            else
            {
                MessageBox.Show("当前没有数据！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        private void textBox3_TextChanged(object sender, EventArgs e)
        {
            if (textBox3.Text.Length != 0)
            {
                if (isNumber(textBox3.Text.Trim()) == false)
                {
                    MessageBox.Show("请输入数字!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    textBox3.Text = "";
                    return;
                }
            }
        }

        private void textBox4_TextChanged(object sender, EventArgs e)
        {
            if (textBox4.Text.Length != 0)
            {
                if (isNumber(textBox4.Text.Trim()) == false)
                {
                    MessageBox.Show("请输入数字!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    textBox4.Text = "";
                    return;
                }
            }
        }

        private void button6_Click(object sender, EventArgs e)
        {
            if (textBox3.Text.Trim() == "")
            {
                MessageBox.Show("请输入当前地址!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                textBox3.Focus();
                return;
            }
            if (textBox4.Text.Trim() == "")
            {
                MessageBox.Show("请输入新地址!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                textBox4.Focus();
                return;
            }
            try
            {
                Log.WriteLog("开始设置设备新地址。");
                if (OpenSerial() == true)
                {
                    const UInt16 registerStartAddr = 0;
                    byte[] data = new byte[2];
                    deviceAddr = Convert.ToByte(textBox3.Text.Trim());
                    UInt16 newAddr = Convert.ToUInt16(textBox4.Text.Trim());
                    data[0] = (byte)(newAddr >> 8);//高位
                    data[1] = (byte)(newAddr & 0xff);
                    Log.WriteLog("把旧地址" + deviceAddr.ToString() + "设置新地址:" + newAddr.ToString());
                    byte[] sendData = modbus.GetDataForWriteHoldingRegister(deviceAddr, registerStartAddr, 1, 2, data);
                    if (SendWriteHoldingRegisterDataAndVerify(sendData, registerStartAddr, 1) == true)
                    {
                        deviceAddr = (byte)newAddr;
                        int countOfData = 0;
                        Thread.Sleep(delayTime);
                        if (ReadPlanCountOfDataFromDevice(ref countOfData) == true)//使用这个寄存器来测试
                        {
                            Log.WriteLog("设置新地址成功!");
                            MessageBox.Show("设置新地址成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        }
                        else
                        {
                            Log.WriteLog("验证新地址出错。");
                            return;
                        }
                    }
                    else
                    {
                        Log.WriteLog("设置新地址出错!");
                        MessageBox.Show("设置新地址出错!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    serialPort1.Close();
                }
                else
                {
                    Log.WriteLog("打开串口出错！");
                    serialPort1.Close();
                }
            }
            catch (Exception ex)
            {
                Log.WriteLog(ex.Message);
                Log.WriteLog(ex.StackTrace);
                serialPort1.Close();
            }
        }

        private bool TestDeviceAddress(ref int addr)
        {
            /*
 * 高精度温度传感器直接读取设备地址：
自定义功能码 100
FF 64 00 00 00 01 XX  XX（广播地址255 功能码100 寄存器地址00 00 读取长度 00 01 校验码XX XX）
 */
            Log.WriteLog("开始读取设备地址：" + addr.ToString());
            byte[] data = new byte[8];
            data[0] = 0xff;
            data[1] = 0x64;
            data[2] = 0;
            data[3] = 0;
            data[4] = 0;
            data[5] = 1;
            UInt16 checkSum = modbus.Get_Crc_16(data, 6);//校验,2字节
            data[6] = (byte)((checkSum >> 8) & 0xFF);
            data[7] = (byte)(checkSum & 0xFF);

            byte[] receiveData = new byte[2]; //只有2个字节
            byte receiveDataLength = 0;
            bool returnValue = SendCheckDeviceAddrMsg(data, 1, ref receiveDataLength, ref receiveData);
            if (returnValue == true && receiveDataLength == 2)
            {
                addr = receiveData[0] * 256 + receiveData[1];
                Log.WriteLog("从设备里读取到的设备地址为" + addr.ToString());

            }
            else
            {
                Log.WriteLog("读取设备地址：数据长度不对或没有收到数据。");
                return false;
            }
            return returnValue;
        }

        private void button7_Click(object sender, EventArgs e)
        {
            try
            {
                if (OpenSerial() == true)
                {
                    comboBox3.Items.Clear();
                    comboBox3.Text = "";
                    activeDeviceList.Clear();

                    label7.Text = label7Str + "正在侦测在线设备，请稍候...";
                    int addr = 0;

                    if (TestDeviceAddress(ref addr) == true)
                    {
                        string deviceName = "device_" + addr.ToString();
                        activeDeviceList.Add(deviceName, addr);
                        comboBox3.Items.Add(deviceName);
                    }

                    if (comboBox3.Items.Count > 0)
                    {
                        comboBox3.SelectedIndex = 0;
                    }
                    serialPort1.Close();
                    label7.Text = label7Str + "一共侦测到" + comboBox3.Items.Count + "个设备.";
                }
                else
                {
                    Log.WriteLog("打开串口出错！");
                    serialPort1.Close();
                }
            }
            catch (Exception ex)
            {
                Log.WriteLog(ex.Message);
                Log.WriteLog(ex.StackTrace);
                serialPort1.Close();
            }
        }

        //定时检测串口
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen == false)
            {
                comboBox1.Items.Clear();
                comboBox1.Text = "";
                foreach (string portName in SerialPort.GetPortNames())
                {
                    //if (comboBox1.Items.Contains(portName) == false)
                    {
                        comboBox1.Items.Add(portName);
                    }
                }
                if (comboBox1.Items.Count != 0)
                {
                    comboBox1.SelectedIndex = 0;
                }
            }
        }

        private void 校准ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (comboBox3.Items.Count != 0)
            {
                string[] tmp = comboBox3.Text.Split('_');
                if (tmp.Length == 2)
                {
                    modbus.PortName = comboBox1.Text.Trim();
                    modbus.DeviceAddr = Convert.ToByte(tmp[1]);
                    calibration calibra = new calibration();
                    calibra.ShowDialog();
                }
                else
                {
                    MessageBox.Show("当前设备地址无效，需要先侦测在线设备！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
            else
            {
                MessageBox.Show("当前在线设备为0，需要先侦测在线设备！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

        }

        private void 硬件版本ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (comboBox3.Items.Count != 0)
            {
                string[] tmp = comboBox3.Text.Split('_');
                if (tmp.Length == 2)
                {
                    modbus.PortName = comboBox1.Text.Trim();
                    modbus.DeviceAddr = Convert.ToByte(tmp[1]);
                    Version ver = new Version();
                    ver.ShowDialog();
                }
                else
                {
                    MessageBox.Show("当前设备地址无效，需要先侦测在线设备！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
            else
            {
                MessageBox.Show("当前在线设备为0，需要先侦测在线设备！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }
    }
}
